package com.nowcoder.community.service;

import com.nowcoder.community.controller.exception.PageErrorException;
import com.nowcoder.community.entity.Comment;
import com.nowcoder.community.entity.DiscussPost;
import com.nowcoder.community.entity.Page;
import com.nowcoder.community.entity.User;
import com.nowcoder.community.event.CommentEvent;
import com.nowcoder.community.event.producer.DefaultEventProducer;
import com.nowcoder.community.mapper.CommentMapper;
import com.nowcoder.community.mapper.DiscussPostMapper;
import com.nowcoder.community.dao.EntityLikeDao;
import com.nowcoder.community.mapper.UserMapper;
import com.nowcoder.community.util.Constants;
import com.nowcoder.community.util.HostHolder;
import com.nowcoder.community.util.SensitiveWordFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;

import java.util.*;

@Service
public class CommentService {
    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DiscussPostMapper discussPostMapper;

    @Autowired
    private EntityLikeDao entityLikeDao;

    @Autowired
    HostHolder hostHolder;

    @Autowired
    DefaultEventProducer defaultEventProducer;

    private void sendCommentEvent(int postId, int entityId, Comment comment) {
        defaultEventProducer.sendCommentEvent((CommentEvent) new CommentEvent()
                .setCommentUserId(comment.getUserId())
                .setPostId(postId)
                .setEntityId(entityId)
                .setEntityType(Constants.ENTITY_TYPE_COMMENT)
                .setUserIdOfEntity(comment.getTargetId())
                .setCreateTime(comment.getCreateTime().getTime()));
    }


    /**
     * 查找某实体的所有评论信息, 支持分页.
     * version: 1.0.1 优化相同用户评论重复查询用户信息的问题.
     */
    public List<Comment> findCommentsByEntity(int entityId, int entityType, Page page) {
        List<Comment> comments = commentMapper.selectPageByEntity(entityId,
                entityType,
                page.getOffset(), page.getLimit());

        Map<Integer, User> userMap = new HashMap<>();
        User user;
        // 获取每个评论的所属用户与评论回复
        for (Comment comment : comments) {
            if ((user = userMap.get(comment.getUserId())) == null) {
                user = userMapper.selectById(comment.getUserId());
                userMap.put(comment.getUserId(), user);
            }
            comment.setUser(user);
            comment.setLikeCount(entityLikeDao.selectEntityLikeCount(Constants.ENTITY_TYPE_COMMENT, comment.getId()));
            if (hostHolder.getUser() != null) {
                comment.setLikeStatus(entityLikeDao.getLikeStatus(hostHolder.getUser().getId(), Constants.ENTITY_TYPE_COMMENT, comment.getId()));
            }


            List<Comment> replies = commentMapper.selectPageByEntity(comment.getId(),
                    Constants.ENTITY_TYPE_COMMENT,
                    0, Integer.MAX_VALUE);

            for (Comment reply : replies) {
                if ((user = userMap.get(reply.getUserId())) == null) {
                    user = userMapper.selectById(reply.getUserId());
                    userMap.put(reply.getUserId(), user);
                }
                reply.setUser(user);
                reply.setLikeCount(entityLikeDao.selectEntityLikeCount(Constants.ENTITY_TYPE_COMMENT, reply.getId()));
                if (hostHolder.getUser() != null) {
                    reply.setLikeStatus(entityLikeDao.getLikeStatus(hostHolder.getUser().getId(), Constants.ENTITY_TYPE_COMMENT, reply.getId()));
                }

                if (reply.getTargetId() != null) {
                    Comment r = replies.stream()
                            .filter(i -> Objects.equals(reply.getTargetId(), i.getUserId())).findFirst()
                            .orElse(null);
                    reply.setTarget(r == null ? null : r.getUser());
                }
            }

            comment.setReplies(replies);
        }
        return comments;
    }

    /**
     * 在某帖子下添加评论.
     */
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void addPostComment(int postId, Comment comment) {
        if (comment.getEntityType() == null) {
            throw new PageErrorException("无效的回复类型.");
        }

        // 回复某评论, 检验此评论是否存在
        Comment targetComment;
        if (comment.getEntityType() == Constants.ENTITY_TYPE_COMMENT) {
            if ((targetComment = commentMapper.selectById(comment.getEntityId())) == null) {
                throw new PageErrorException("无效的回复对象");
            }
            comment.setTargetId(targetComment.getUserId());
        }

        // 回复某帖子, 检验此帖子是否存在
        DiscussPost targetPost;
        if (comment.getEntityType() == Constants.ENTITY_TYPE_POST) {
            if ((targetPost = discussPostMapper.selectById(comment.getEntityId())) == null) {
                throw new PageErrorException("无效的回复对象");
            }
            comment.setTargetId(targetPost.getUserId());
        }

        comment.setContent(HtmlUtils.htmlEscape(comment.getContent()));
        comment.setContent(SensitiveWordFilter.filter(comment.getContent()));
        comment.setStatus(0);
        commentMapper.insert(comment);
        if (comment.getEntityType() == Constants.ENTITY_TYPE_POST) {
            discussPostMapper.addCommentCountById(comment.getEntityId(), 1);
        }
        sendCommentEvent(postId, comment.getId(), comment);
    }
}
